package middleware

/*
	此文件内容为：验证身份的中间件
*/

import (
	"github.com/gin-gonic/gin"
	"net/http"
	"time"
	"yun_image/config/api"
	"yun_image/config/user"
	"yun_image/entity"
	"yun_image/service"
	"yun_image/util"
)

var (
	// 不需要身份验证的api路径，直接放行
	excludePaths = api.ExcludePaths
	// token有效时间，毫秒
	timeOut = user.TimeOut
	// 允许使用系统时，用户状态state的值
	stateOk = user.StateOk
)

// verifyToken verifyState verifyApiAccess 对请求进的token验证，注意某些路径不需要身份验证，比如登陆注册

// verifyToken对token进行验证
func verifyToken(context *gin.Context) {
	if util.IndexOf[string](excludePaths, context.FullPath(), len(excludePaths)) != -1 {
		// 如果请求路径为放行的api，例如如登陆、注册，直接执行后续的handler
		context.Next()
		return
	}
	// 这里ok意思是是否执行后续组件
	ok, token := true, context.GetHeader("token")
	account := util.UserTokenUtil.GetAccount(token)
	if account == "" {
		ok = false //token不存在
	}
	lastTime := util.UserTokenUtil.GetTime(token)
	if time.Now().UnixMilli()-lastTime > timeOut {
		ok = false //token过期
	}
	if ok {
		//执行后续的handler
		context.Next()
	} else {
		// 响应前端，告诉前端身份验证失败
		context.JSON(http.StatusOK, gin.H{
			"authorizeNotOk": true,
		})
		// 不执行后续的handler，需要调用Abort函数，才能终止后面handler的执行
		context.Abort()
	}
}

// verifyState对用户状态进行验证
func verifyState(context *gin.Context) {
	if util.IndexOf[string](excludePaths, context.FullPath(), len(excludePaths)) != -1 {
		// 如果请求路径为放行的api，例如如登陆、注册，直接执行后续的handler
		context.Next()
		return
	}
	token := context.GetHeader("token")
	var user entity.User
	err := service.GetUserByToken(&user, token)
	if err != nil {
		context.String(http.StatusInternalServerError, "")
		context.Abort()
		return
	}
	if user.State != stateOk {
		// 用户的state值不是正常值，不允许使用系统
		context.JSON(http.StatusOK, gin.H{
			"stateNotOk": true,
		})
		context.Abort()
	} else {
		// 在第一个用到user的handler里把user存起来，后续handler中通过Get函数和强转可以获得user对象
		// 这样做可以避免在一次http请求的处理中反复查询数据库获得user信息，提高系统效率
		context.Set("user", user)
		context.Next()
	}
}

// verifyApiAccess 对用户是否有权限访问该接口进行验证
func verifyApiAccess(context *gin.Context) {
	if util.IndexOf[string](excludePaths, context.FullPath(), len(excludePaths)) != -1 {
		// 如果请求路径为放行的api，例如如登陆、注册，直接执行后续的handler
		context.Next()
		return
	}

	var user entity.User
	userVal, _ := context.Get("user")
	user, _ = userVal.(entity.User)

	var result bool
	err := service.CheckApiAccess(&result, context.FullPath(), user.RoleId)
	if err != nil {
		// 用户没有该api接口的权限，不能使用该接口
		context.String(http.StatusInternalServerError, "")
		context.Abort()
		return
	}

	if result {
		context.Next()
	} else {
		context.JSON(http.StatusOK, gin.H{
			"apiAccessNotOk": true,
		})
		context.Abort()
	}
}

// verifyUserFrequency 检测用户访问是否过于频繁
func verifyUserFrequency(context *gin.Context) {
	if util.IndexOf[string](api.FrequencyLimitExcludePaths, context.FullPath(), len(api.FrequencyLimitExcludePaths)) != -1 {
		context.Next()
		return
	}
	var user entity.User
	userVal, _ := context.Get("user")
	user, _ = userVal.(entity.User)
	util.AccountFrequencyRecord.Add(user.Account)
	if util.AccountFrequencyRecord.Check(user.Account) {
		context.JSON(http.StatusOK, gin.H{
			"tooFrequent": true,
		})
		context.Abort()
		return
	} else {
		context.Next()
	}
}
func UseAuthorize(router *gin.Engine) {
	router.Use(verifyToken)
	router.Use(verifyState)
	router.Use(verifyApiAccess)
	router.Use(verifyUserFrequency)
}
